import path from 'path'
import _ from 'lodash'
import ffmpegStatic from "ffmpeg-static";
import shell from 'any-shell-escape'
import child_process from 'child_process'
import makeDir from 'make-dir'
import ffprobe from 'ffprobe'
import ffprobeStatic from 'ffprobe-static'
import utils from '@/services/utils'
import remoteTools from '@/services/remoteTools'

const ffmpegPath = process.env.NODE_ENV !== 'development' ? ffmpegStatic.replace('app.asar', 'app.asar.unpacked'): ffmpegStatic;
const exec = child_process.exec;
// console.log(ffmpegPath);

function runShellCommand(arr) {
  return new Promise( (resolve, reject) => {
    const command = shell(arr)
    exec(command, (err) => {
      if (err) {
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

function runShellCommandString(str) {
  return new Promise( (resolve, reject) => {
    exec(str, (err) => {
      if (err) {
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

// 截取视频
async function splitVideo(input, start, duration, output) {
  try {
    const commandArr = [
      ffmpegPath,
      '-ss', start,
      '-t', duration,
      '-i', input,
      '-vcodec', 'copy',
      '-acodec', 'copy',
      output
    ];
    await runShellCommand(commandArr);
    return output;
  } catch (error) {
    throw error;
  }
}

// 转尺寸 (模式1，强制拉伸，画面可能会变形)
async function resizeVideoMode1(input, size, output) {
  try {
    const command = `${ffmpegPath} -i ${input} -s ${size} ${output}`;
    await runShellCommandString(command);
    return output;
  } catch (error) {
    throw error;
  }
}

// 转尺寸 (模式2，填充背景模糊)
async function resizeVideoMode2(input, width, height, output) {
  try {
    // 获取视频宽高
    const parsed = await ffprobe(input, { path: ffprobeStatic.path });
    const info = _.find(parsed.streams, { codec_type: 'video' });
    // 计算比例
    const inputScale = info.height / info.width; 
    const outScale = height / width;
    let tmpOutput = path.resolve(remoteTools.getTmpDir(), 'inmobi', 'tmpvid_' + _.random(99999999) + '.mp4');
    let command;
    // 添加背景模糊
    // 比例相同，无需填充
    if (inputScale === outScale) {
      return output;
    } else if (inputScale > outScale) {
      // 左右填充
      console.log('左右填充');
      command = `${ffmpegPath} -i ${input} -lavfi '[0:v]scale=ih*${width}/${height}:-2,boxblur=luma_radius=min(h\\,w)/20:luma_power=1:chroma_radius=min(cw\\,ch)/20:chroma_power=1[bg];[bg][0:v]overlay=(W-w)/2:(H-h)/2,crop=h=iw*${height}/${width}' -vb 800K ${tmpOutput}`;
    } else {
      // 上下填充
      console.log('上下填充');
      command = `${ffmpegPath} -i ${input} -lavfi '[0:v]scale=-2:iw*${height}/${width},boxblur=luma_radius=min(h\\,w)/20:luma_power=1:chroma_radius=min(cw\\,ch)/20:chroma_power=1[bg];[bg][0:v]overlay=(W-w)/2:(H-h)/2,crop=w=ih*${width}/${height}' -vb 800K ${tmpOutput}`;
    }
    console.log(command);
    await runShellCommandString(command);
    // 转换尺寸
    await utils.sleep(300);
    // const command2 = `${ffmpegPath} -i ${tmpOutput} -s ${width}*${height} ${output}`;
    // fix error “height not divisible by 2”
    const command2 = `${ffmpegPath} -i ${tmpOutput} -vf scale="ceil(${width}/2)*2:ceil(${height}/2)*2" ${output}`;
    // console.log(command);
    await runShellCommandString(command2);
    return output;
  } catch (error) {
    throw error;
  }
}

// 转尺寸 (模式3, 裁切)
async function resizeVideoMode3(input, width, height, output) {
  try {
    // 获取视频宽高
    const parsed = await ffprobe(input, { path: ffprobeStatic.path });
    const info = _.find(parsed.streams, { codec_type: 'video' });
    // 计算比例
    const inputScale = info.height / info.width; 
    const outScale = height / width;
    let command;
    // 添加背景模糊
    // 比例相同，无需填充
    if (inputScale === outScale) {
      return output;
    } else if (inputScale > outScale) {
      // 上下裁切
      console.log('上下裁切');
      command = `${ffmpegPath} -i ${input} -strict -2 -vf "scale=${width}:-2,crop=${width}:${height}:0:(${width}-iw*${height}/${width})/2" ${output}`;
    } else {
      // 左右裁切
      console.log('左右裁切');
      command = `${ffmpegPath} -i ${input} -strict -2 -vf "scale=-2:${height},crop=${width}:${height}:(${height}-ih*${width}/${height})/2:0" ${output}`;
    }
    await runShellCommandString(command);
    return output;
  } catch (error) {
    throw error;
  }
}

// 添加视频后贴片 (不改尺寸,同规格视频适用)
async function concatTwoVideo(video1, video2, output) {
  try {
    const command = `${ffmpegPath} -i ${video1} -i ${video2} -filter_complex '[0:0] [0:1] [1:0] [1:1] concat=n=2:v=1:a=1:unsafe=1 [v] [a]' -map '[v]' -map '[a]' ${output}`;
    await runShellCommandString(command)
    return output;
  } catch (error) {
    throw error;
  }
}

// 添加视频后贴片 (按照指定尺寸)
async function concatTwoVideoWithSize(video1, video2, size, output) {
  try {
    const command = `${ffmpegPath} -i ${video1} -i ${video2} -filter_complex "[0:v]scale=${size}:force_original_aspect_ratio=decrease[v0];[v0]pad=${size}:(ow-iw)/2:(oh-ih)/2:black[v1];[1:v]scale=${size}:force_original_aspect_ratio=decrease[v2];[v2]pad=${size}:(ow-iw)/2:(oh-ih)/2:black[v3];[v1][0:a][v3][1:a]concat=n=2:v=1:a=1[v][a]" -map "[v]" -map "[a]" -c:v libx264 -c:a aac -movflags +faststart ${output}`;
    await runShellCommandString(command)
    return output;
  } catch (error) {
    throw error;
  }
}

// 替换背景音乐
async function replaceBgAudio(input, audio, output) {
  try {
    const command = `${ffmpegPath} -i ${input} -i ${audio} -c:v copy -c:a aac -strict experimental -map 0:v:0 -map 1:a:0 ${output}`;
    await runShellCommandString(command)
    return output;
  } catch (error) {
    throw error;
  }
}

// 转尺寸并添加蒙版
async function resizeAndAddWatermark(input, size, watermark, output, x = '0', y = '0') {
  try {
    const command = `${ffmpegPath} -i ${input} -s ${size} -vf "movie=${watermark}[watermark];[in][watermark] overlay=x=${x}:y=${y}[out]" ${output}`;
    await runShellCommandString(command)
    return output;
  } catch (error) {
    throw error;
  }
}

// 添加 inmobi 审核水印
async function addInmobiAuditWatermark(input, output) {
  try {
    let watermark = path.join(__static, '/imgs/audit_watermark_1080x212.png');
    // 解决打包后 asar 内的文件访问不到
    if (process.env.NODE_ENV !== 'development') {
      watermark = watermark.replace('app.asar', 'app.asar.unpacked')
    }
    const command = `${ffmpegPath} -i ${input} -i ${watermark} -filter_complex "[1:v][0:v]scale2ref=iw:212*iw/1080[wm][base];[base][wm]overlay=0:(main_h-overlay_h)/2" -codec:a copy ${output}`;
    console.log(command);
    await runShellCommandString(command);
    return output;
  } catch (error) {
    throw error;
  }
}

// 模板一生成过程 
async function makeTemplateVideo1(input, coverImg, resizeType, replaceAudio) {
  try {
    // 创建缓存文件夹
    await makeDir(path.resolve(remoteTools.getTmpDir(), 'inmobi'));
    // 第 1 步
    console.log(`第 1 步： 截取视频`);
    const splitOutput = path.resolve(remoteTools.getTmpDir(), 'inmobi', 'split_' + Math.floor(Math.random()*10000+0) + '.mp4');
    await splitVideo(input, '00:00:00', '00:00:13', splitOutput);
    console.log('处理成功');
    await utils.sleep(300);
    // 第 2 步, 视频转尺寸 (可能有3种模式)
    console.log(`第 2 步： 视频转尺寸`);
    console.log(`resizeType=${resizeType}`);
    const resizeOutput = path.resolve(remoteTools.getTmpDir(), 'inmobi', 'resize_' + Math.floor(Math.random()*10000+0) + '.mp4');
    switch (resizeType) {
      case '2':
        await resizeVideoMode2(splitOutput, 720, 1280, resizeOutput);
        break;
      case '3':
        await resizeVideoMode3(splitOutput, 720, 1280, resizeOutput);
        break;
      default:
        await resizeVideoMode1(splitOutput, '720*1280', resizeOutput)
        break;
    }
    console.log('处理成功');
    await utils.sleep(300);
    // 第 3 步
    console.log(`第 3 步： 添加文字、图片水印`);
    let watermark = coverImg || path.join(__static, '/imgs/template1-cover.png');
    // 解决打包后 asar 内的文件访问不到
    if (process.env.NODE_ENV !== 'development') {
      watermark = watermark.replace('app.asar', 'app.asar.unpacked')
    }
    const concatOutput = path.resolve(remoteTools.getTmpDir(), 'inmobi', 'concat_' + Math.floor(Math.random()*10000+0) + '.mp4');
    await resizeAndAddWatermark(resizeOutput, '720*1280', watermark, concatOutput, '0', '0');
    console.log('处理成功');
    await utils.sleep(300);
    // 第 4 步
    console.log(`第 4 步： 添加后贴片`);
    let endVideo = path.join(__static, '/imgs/end.mp4');
    // 解决打包后 asar 内的文件访问不到
    if (process.env.NODE_ENV !== 'development') {
      endVideo = endVideo.replace('app.asar', 'app.asar.unpacked')
    }
    const outputPath = path.resolve(remoteTools.getDownloadDir(), 'video-batch-maker', `output-${Math.floor(Math.random()*10000+0)}.mp4`);
    await concatTwoVideoWithSize(concatOutput, endVideo, '720:1280', outputPath)
    console.log('处理成功');
    // 第 5 步, 替换背景音乐（可选）
    if (replaceAudio) {
      console.log(`第 5 步, 替换背景音乐`);
      const outputPath2 = path.resolve(remoteTools.getDownloadDir(), 'video-batch-maker', `output-${_.random(99999999)}.mp4`);
      await replaceBgAudio(outputPath, replaceAudio, outputPath2);
      console.log(`处理成功`);
      return outputPath2;
    } else {
      return outputPath;
    }
  } catch (error) {
    console.log(error);
    throw error;
  }
}

// 模板2 生成过程  (改变视频尺寸)
async function makeTemplateVideo2(input, resizeType, resizeWidth, resizeHeight) {
  try {
    // 创建缓存文件夹
    await makeDir(path.resolve(remoteTools.getDownloadDir(), `video-batch-maker/${resizeWidth}x${resizeHeight}`));
    // 视频转尺寸 (可能有3种模式)
    // console.log(`视频转尺寸`);
    const resizeOutput = path.resolve(remoteTools.getDownloadDir(), `video-batch-maker/${resizeWidth}x${resizeHeight}`, path.basename(input));
    switch (resizeType) {
      case '2':
        await resizeVideoMode2(input, Number(resizeWidth), Number(resizeHeight), resizeOutput);
        break;
      case '3':
        await resizeVideoMode3(input, Number(resizeWidth), Number(resizeHeight), resizeOutput);
        break;
      default:
        await resizeVideoMode1(input, `${resizeWidth}*${resizeHeight}`, resizeOutput)
        break;
    }
    console.log('处理成功');
    return resizeOutput;
  } catch (error) {
    console.log(error);
    throw error;
  }
}

// 模板3 生成过程  (批量添加审核水印)
async function makeTemplateVideo3(input) {
  try {
    // 创建缓存文件夹
    await makeDir(path.resolve(remoteTools.getDownloadDir(), `video-batch-maker/with-watermark`));
    // 视频转尺寸 (可能有3种模式)
    console.log(`批量添加审核水印`);
    const output = path.resolve(remoteTools.getDownloadDir(), `video-batch-maker/with-watermark`, path.basename(input));
    await addInmobiAuditWatermark(input, output);
    console.log('处理成功');
    return output;
  } catch (error) {
    console.log(error);
    throw error;
  }
}

export default {
  makeTemplateVideo1,
  makeTemplateVideo2,
  makeTemplateVideo3,
}